#pragma once

#include <iostream>
#include <string>
#include <queue>
#include <pthread.h>

using namespace std;

const static int defaultcap = 5;
template <typename T>

class BlockQueue
{
private:
    // 阻塞队列满了
    bool IsFull()
    {
        return _block_queue.size() == _max_cap;
    }

    bool IsEmpty()
    {
        return _block_queue.empty();
    }

public:
    BlockQueue(int cap = defaultcap) : _max_cap(cap)
    {
        // 判断???
        _highcap = (cap / 4) * 3;
        _lowcap = cap / 4;

        pthread_mutex_init(&_mutex, nullptr); // 初始化互斥锁
        pthread_cond_init(&_p_cond, nullptr); // 初始化生产者条件变量
        pthread_cond_init(&_c_cond, nullptr); // 初始化消费者条件变量
    }

    void Pop(T *out)
    {
        //为何在阻塞队列里，生产者和消费者共用一把锁，而环形队列里，生产者和消费者各用自己的锁？？？(***)
        pthread_mutex_lock(&_mutex);

        // if (IsEmpty())
        // {
        //     //添加尚未满足，但是线程被异常唤醒的情况，叫做伪唤醒
        //     //解决方法：将判断的if改为while
        //     pthread_cond_wait(&_c_cond, &_mutex);
        // }
        while (IsEmpty())
        {
            pthread_cond_wait(&_c_cond, &_mutex);
        }

        // a.阻塞队列没满 || b.被唤醒了
        *out = _block_queue.front();
        _block_queue.pop();

        pthread_mutex_unlock(&_mutex);
        // 让生产者生产
        //if (_block_queue.size() <= _lowcap)
            pthread_cond_signal(&_p_cond); // 将生产者唤醒
    }

    void Equeue(const T &in) // push
    {
        pthread_mutex_lock(&_mutex);

        while (IsFull()) // if ? --->while
        {
            // 阻塞队列满了，生产者要停止生产，进行等待

            // 该线程在临界区里阻塞等待了，其他线程怎么办???
            // pthread_cond_wait被调用的时候，除了让自己进行排队等待，还会自己释放传入的锁
            // 该函数返回时，还在临界区吗???
            // 返回时，必须线参与锁的竞争，重新加上锁，该函数才会返回
            pthread_cond_wait(&_p_cond, &_mutex);
        }
        // a.阻塞队列没满 || b.被唤醒了
        _block_queue.push(in); // 生产到阻塞队列

        pthread_mutex_unlock(&_mutex);
        // 让消费者消费
        //if (_block_queue.size() > _highcap)
            pthread_cond_signal(&_c_cond); // 将消费者叫醒
    }

    ~BlockQueue()
    {
        pthread_mutex_destroy(&_mutex);
        pthread_cond_destroy(&_p_cond);
        pthread_cond_destroy(&_c_cond);
    }

private:
    queue<T> _block_queue; // 必须是临界资源
    int _max_cap;
    pthread_mutex_t _mutex;
    pthread_cond_t _p_cond; // 生产者条件变量
    pthread_cond_t _c_cond; // 消费者条件变量

    int _highcap;
    int _lowcap;
};
